# -*-coding:utf-8-*-
import threading
from functools import wraps
# 方式一,new()是类实例化对象时被触发的第一个方法,用来实例化一个空对象并返回,紧接着init()接收这个空对象进行初始化操作,
# !!!此方式产生单例对象时会多次执行init()!!!
class Person(object):
    __instance = None
    __instance_lock = threading.Lock()  # 加锁,保证多线程下的单例

    def __init__(self, x):
        self.x = x

    def __new__(cls, *args, **kwargs):
        with cls.__instance_lock:
            if not cls.__instance:
                cls.__instance = super().__new__(cls)
        return cls.__instance

# 方式二,利用类方法实现单例,init()只执行一次
class Person2:
    __instance = None
    __instance_lock = threading.Lock()  # 加锁,保证多线程下的单例

    def __init__(self, x):
        self.x = x

    @classmethod
    def get_instance(cls, x):
        with cls.__instance_lock:
            if not cls.__instance:
                cls.__instance = cls(x)
        return cls.__instance

# 方式三,利用装饰器实现单例
"""
等效的嵌套函数实现的装饰器
def singleton(clazz):
    instance = None
    @wraps(clazz)
    def wrapper(*args, **kwargs):
        nonlocal instance
        if instance is None:
            instance = clazz(*args, **kwargs)
        return instance
    return wrapper
"""
class singleton(object):

    def __init__(self, clazz):
        wraps(clazz)(self)
        self.__instance = None  # 注意不能写成类变量

    def __call__(self, *args, **kwargs):
        if self.__instance is None:
            self.__instance = self.__wrapped__(*args, **kwargs)
        return self.__instance

@singleton
class Person3(object):
    def __init__(self, x):
        self.x = x

# 方式三,利用元类实现单例
class SingletonMeta(type):
    def __init__(cls, *args, **kwargs):
        super().__init__(*args, **kwargs)
        cls.__instance = None

    def __call__(cls, *args, **kwargs):
        if cls.__instance is None:
            cls.__instance = super().__call__(*args, **kwargs)
        return cls.__instance

class Person4(object, metaclass=SingletonMeta):
    def __init__(self, x):
        self.x = x

if __name__ == '__main__':
    print(Person(1) is Person(2))
    print(Person2.get_instance(1) is Person2.get_instance(2))
    print(Person3(1) is Person3(2))
    print(Person4(1) is Person4(2))